package API.Class.util.TCP.Server;

import API.Class.Collections.SameThreadCollections;
import API.Class.util.TCP.Interactions;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.*;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

/**
 * 此类为被实例化的类的线程为依据，进行存储数据
 * <p>
 * 它还可以读取实例化的时候线程的对象
 * </p>
 */
public class TCP_ServerSocket {
    static SameThreadCollections<ArrayList<Socket>> ClientSockets;//客户端套接字集合
    private ServerSocket socket;
    private String IPv4;//服务器ipv4地址
    private String IPv6;//服务器ipv6地址
    private int port;//服务器端口
    static SameThreadCollections<HashSet<String>> BlackList;//黑名单列表
    static SameThreadCollections<CheckClient> CheckForClient;//检查客户端是否正确
    static SameThreadCollections<Integer> MaxConnect;//服务器最大连接数
    static SameThreadCollections<Integer> CurrentConnect;//当前连接数
    static SameThreadCollections<ExecutorService> ThreadPool;//线程池
    static SameThreadCollections<Constructor> handleClient;//处理用户

    public ArrayList<Socket> getClientSockets() {
        return ClientSockets.Get();
    }

    public ArrayList<Socket> CheckAndGetClientSockets() {
        CheckConnectState();
        return ClientSockets.Get();
    }

    public void SetMaxConnect(int size) {
        MaxConnect.Add(size + 1);
    }

    public int GetMaxConnect() {
        return MaxConnect.Get() - 1;
    }

    public Set<String> getClientIP() {
        Iterator<Socket> iterator = ClientSockets.Get().iterator();
        Set<String> cache = new HashSet<>();
        while (iterator.hasNext()) {
            cache.add(iterator.next().getInetAddress().getHostAddress());
        }
        return cache;
    }

    public synchronized void CheckConnectState() {
        Iterator<Socket> iterator = ClientSockets.Get().iterator();
        while (iterator.hasNext()) {
            Socket socket = iterator.next();
            if (socket.isClosed()) {
                ClientSockets.Get().remove(socket);
                CurrentConnect.Add(TCP_ServerSocket.CurrentConnect.Get().intValue() - 1);
            }
        }
    }

    public void close() throws IOException {
        socket.close();
    }

    public void CheckForClient(CheckClient clientCheck) {
        CheckForClient.Add(clientCheck);
    }


    /**
     * @param port         服务器端口
     * @param MaxConnect   服务器最大连接数
     * @param interactions 验证成功后和客户端交互
     */
    public TCP_ServerSocket(int port, int MaxConnect, Class<? extends Interactions> interactions) {
        // 获取Listen类的构造函数
        try {
            handleClient.Add(interactions.getConstructor(Socket.class));
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        this.port = port;
        TCP_ServerSocket.MaxConnect.Add(MaxConnect + 1);
    }

    public void RemoveBlackIP(String BlackIP) {
        BlackList.Get().remove(BlackIP);
    }

    public boolean containsBlack(String BlackIP) {
        return BlackList.Get().contains(BlackIP);
    }

    public void AddBlackList(String BlackIP) {
        BlackList.Get().add(BlackIP);
    }

    public Set<String> getBlackList() {
        return BlackList.Get();
    }


    {
        if (BlackList == null) BlackList = new SameThreadCollections<>();
        if (CheckForClient == null) CheckForClient = new SameThreadCollections<>();
        if (ClientSockets == null) ClientSockets = new SameThreadCollections<>();
        if (MaxConnect == null) MaxConnect = new SameThreadCollections<>();
        if (CurrentConnect == null) CurrentConnect = new SameThreadCollections<>();
        if (ThreadPool == null) ThreadPool = new SameThreadCollections<>();
        if (handleClient == null) handleClient = new SameThreadCollections<>();
    }

    public void Start() throws IOException {
        TCP_ServerSocket.CurrentConnect.Add(0);
        socket = new ServerSocket(port);
        new Thread(new WaitForConnectClient(socket)).start();
    }

    {
        //获取ipv6地址
        Enumeration<NetworkInterface> networkInterfaces = null;
        try {
            networkInterfaces = NetworkInterface.getNetworkInterfaces();
        } catch (SocketException e) {
            throw new RuntimeException(e);
        }
        while (networkInterfaces.hasMoreElements()) {
            NetworkInterface networkInterface = networkInterfaces.nextElement();
            Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
            while (inetAddresses.hasMoreElements()) {
                InetAddress inetAddress = inetAddresses.nextElement();
                if (inetAddress instanceof Inet6Address && !inetAddress.isLinkLocalAddress()) {
                    IPv6 = inetAddress.getHostAddress();

                }
            }
        }
        //获取ipv4地址
        InetAddress localhost = null;
        try {
            localhost = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        }
        IPv4 = localhost.getHostAddress();
    }

    public String getIPv4() {
        return IPv4;
    }

    public int getPort() {
        return port;
    }

    public String getIPv6() {
        return IPv6;
    }


}

class WaitForConnectClient implements Runnable {
    private ServerSocket ServerSocket;

    public WaitForConnectClient(ServerSocket serverSocket) {
        this.ServerSocket = serverSocket;
    }

    @Override
    public void run() {
        while (true) {
            // 等待客户端连接
            try {
                Socket socket = ServerSocket.accept();
                //查看当前连接数是否达到极限
                if (TCP_ServerSocket.CurrentConnect.Get() > TCP_ServerSocket.MaxConnect.Get()) {
                    socket.close();
                    continue;
                }

                //查看是否在黑名单列表中
                if (!TCP_ServerSocket.BlackList.isNull()) {
                    Iterator<String> iterator = TCP_ServerSocket.BlackList.Get().iterator();
                    while (iterator.hasNext()) {
                        if (iterator.next().equals(socket.getInetAddress().getHostAddress())) {
                            socket.close();
                            break;
                        }
                    }
                }
                //查看是否通过最后检查开发者设置的验证是否通过，如果通过就进行连接
                if (!TCP_ServerSocket.CheckForClient.isNull())
                    if (TCP_ServerSocket.CheckForClient.Get().Check(socket)) {
                        ArrayList<Socket> set = TCP_ServerSocket.ClientSockets.Get();
                        if (set == null) set = new ArrayList<>();
                        set.add(socket);
                        TCP_ServerSocket.ClientSockets.Add(set);
                    } else {
                        socket.close();
                    }
                if (TCP_ServerSocket.ThreadPool.isNull()) {
                    TCP_ServerSocket.ThreadPool.Add(Executors.newFixedThreadPool(TCP_ServerSocket.MaxConnect.Get()));
                }
                //创建多线程，用来与用户交互
                TCP_ServerSocket.ThreadPool.Get().execute(new FutureTask((Interactions) TCP_ServerSocket.handleClient.Get().newInstance(socket)));
                TCP_ServerSocket.CurrentConnect.Add(TCP_ServerSocket.CurrentConnect.Get().intValue() + 1);
            } catch (IOException e) {
                Iterator<Socket> iterator = TCP_ServerSocket.ClientSockets.Get().iterator();
                while (iterator.hasNext()) {
                    Socket socket = iterator.next();
                    if (socket.isClosed()) {
                        TCP_ServerSocket.ClientSockets.Get().remove(socket);
                        TCP_ServerSocket.CurrentConnect.Add(TCP_ServerSocket.CurrentConnect.Get().intValue() - 1);
                    }
                }
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            } catch (InstantiationException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }
}